package cn.dengta.webapp.user.entity.userLevel;

import java.util.*;
import javax.annotation.Nullable;

import cn.dengta.common.model.*;
import cn.dengta.context.model.Language;
import cn.dengta.context.model.Option;
import cn.dengta.webapp.base.entity.BizEntity;
import cn.dengta.webapp.base.entity.I18nContent;
import cn.dengta.webapp.user.entity.task.RuleConfig;
import cn.dengta.webapp.user.model.*;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.codeplayer.util.*;

/**
 * 任务规则表
 *
 * @author lgy
 * @since 2022-11-25
 */
@Setter
@Getter
@Accessors(chain = true)
@TableName("dt_user_level_rule")
public class UserLevelRule extends BizEntity implements SwitchSupport {

	/** 图标 */
	String icon;
	/** 名称 */
	String name;
	/** 任务类型：0=新手；1=日常 */
	TaskType type;
	/** 业务类型 */
	UserLevelRuleType ruleType;
	/** 最小经验值 */
	Integer minExp;
	/** 领取最大次数 */
	Integer maxLimit;
	/** 开始时间 */
	Date beginTime;
	/** 结束时间 */
	Date endTime;
	/** 规则JSON配置 */
	String config;
	/** 排序 */
	Integer sort;

	/** 已解析到的配置对象 */
	protected transient RuleConfig resolvedCfg;
	protected transient I18nContent resolvedLanguageCfg;
	private transient ActivityStatusDescriptor statusDescriptor;

	public UserLevelRule init(UserLevelRule input, Date now) {
		this.icon = X.expectNotEmpty(input.icon, icon);
		this.name = X.expectNotNull(input.name, name);
		this.type = X.expectNotNull(input.type, type);
		this.ruleType = X.expectNotNull(input.ruleType, ruleType);
		this.minExp = input.minExp;
		this.maxLimit = X.expectNotNull(input.maxLimit, maxLimit, 1);
		this.beginTime = X.expectNotNull(input.beginTime, beginTime);
		this.endTime = X.expectNotNull(input.endTime, endTime);
		this.sort = X.expectNotNull(input.sort, sort, 0);
		this.config = StringUtil.toString(input.config);
		super.initTime(now);
		super.init(input.status, input.state);
		return this;
	}

	public UserLevelRule init(String name, UserLevelRuleType ruleType, Integer minExp, Date beginTime, Date endTime) {
		this.name = name;
		this.ruleType = ruleType;
		this.minExp = minExp;
		this.beginTime = beginTime;
		this.endTime = endTime;
		return this;
	}

	@Nullable
	public <T extends RuleConfig> T getResolvedCfg() {
		RuleConfig cfg = resolvedCfg;
		if (cfg == null) {
			resolvedCfg = cfg = ruleType.deserialize(config);
		}
		return X.castType(cfg);
	}

	public void updateCfg(RuleConfig taskRuleConfig) {
		this.config = ruleType.serialize(this.resolvedCfg = taskRuleConfig);
	}

	public <T extends RuleConfig> T updateResolvedCfg(String config) {
		this.resolvedCfg = ruleType.deserialize(this.config = config);
		return getResolvedCfg();
	}

	public String getI18nName() {
		return X.map(getResolvedLanguageCfg(), I18nContent::get);
	}

	public String getI18nName(Language language) {
		return X.map(getResolvedLanguageCfg(), l -> l.get(language));
	}

	public boolean forCategory(@Nullable UserLevelRuleCategory category) {
		return ruleType != null && ruleType.category == category;
	}

	@Nullable
	public I18nContent getResolvedLanguageCfg() {
		I18nContent cfg = resolvedLanguageCfg;
		if (cfg == null) {
			resolvedLanguageCfg = cfg = StringUtil.isEmpty(name) ? null : I18nContent.deserialize(name);
		}
		return X.castType(cfg);
	}

	public void updateName(I18nContent config) {
		this.name = I18nContent.serialize(this.resolvedLanguageCfg = config);
	}

	public I18nContent updateResolvedLanguageCfg(String config) {
		this.resolvedLanguageCfg = I18nContent.deserialize(this.name = config);
		return getResolvedLanguageCfg();
	}

	public boolean isActivity(Long nowTime) {
		if (nowTime == null) {
			nowTime = System.currentTimeMillis();
		}
		return isActive(nowTime);
	}

	public ActivityStatusDescriptor getStatusDescriptor(final long baseTime) {
		ActivityStatusDescriptor descriptor = statusDescriptor;
		if (descriptor == null) {
			descriptor = ActivityStatusDescriptor.of(SwitchSupport.statusValue(status > 0, baseTime, beginTime.getTime(), endTime));
			statusDescriptor = descriptor;
		}
		return descriptor;
	}

	@Override
	public boolean isEnabled() {
		return status > 0;
	}

	/**
	 * 用户等级规则枚举
	 */
	@Getter
	public enum UserLevelRuleType implements ValueProxyImpl<UserLevelRuleType, Integer> {
		/** 登录 */
		LOGIN_IN(0, "登录", false, false, true, UserLevelRuleCategory.ACTIVE),
		/** 发布动态 */
		MOMENT_PUSH(1, "发布动态", false, false, true, UserLevelRuleCategory.ACTIVE),
		/** 回复搭讪 */
		REPLY_GREET(2, "回复搭讪", true, false, true, UserLevelRuleCategory.ACTIVE),
		/** 直播 */
		LIVE(3, "直播", true, false, true, UserLevelRuleCategory.ACTIVE),
		/** 直播发言 */
		LIVE_CHAT(4, "直播发言", false, false, true, UserLevelRuleCategory.ACTIVE),
		/** 关注主播 */
		FOLLOW_ANCHOR(5, "关注主播", true, false, true, UserLevelRuleCategory.ACTIVE),
		/** 上传头像 */
		UPLOAD_AVATAR(6, "上传头像", false, false, true, UserLevelRuleCategory.ACTIVE),
		/** 绑定手机 */
		BIND_PHONE(7, "绑定手机", false, false, true, UserLevelRuleCategory.ACTIVE),
		/** 绑定FaceBook */
		BIND_FACE_BOOK(8, "绑定FaceBook", false, false, true, UserLevelRuleCategory.ACTIVE),
		/** 购买VIP */
		BUY_VIP(9, "购买VIP", true, false, VipRuleConfig.class, true, UserLevelRuleCategory.WEALTH),
		/** 消耗钻石 */
		USE_COIN(10, "消耗钻石", true, false, true, UserLevelRuleCategory.WEALTH),
		/** 充值钻石 */
		RECHARGE_COIN(11, "充值钻石", true, false, true, UserLevelRuleCategory.WEALTH),
		/** 消耗金币 */
		USE_GOLD(12, "消耗金币", true, false, true, UserLevelRuleCategory.WEALTH),
		/** 首次充值 */
		FIRST_RECHARGE(13, "首次充值", false, false, true, UserLevelRuleCategory.WEALTH),
		/** 通话评价 */
		CALL_EVAL(14, "通话评价", true, false, true, UserLevelRuleCategory.ACTIVE),
		//
		;
		/** 是否显示 */
		public boolean visible;
		public Integer value;
		public boolean innerSet;
		/** 是否需要重复校验 */
		public boolean repeatCheck;
		public UserLevelRuleCategory category;
		public final Class<? extends RuleConfig> configClazz;
		final ValueProxy<UserLevelRuleType, Integer> proxy;
		//

		UserLevelRuleType(Integer value, String label, boolean repeatCheck, boolean innerSet, Class<? extends RuleConfig> configClazz, boolean visible, UserLevelRuleCategory category) {
			this.value = value;
			this.visible = visible;
			this.innerSet = innerSet;
			this.repeatCheck = repeatCheck;
			this.category = category;
			this.configClazz = configClazz;
			this.proxy = new ValueProxy<>(this, value, label);
		}

		UserLevelRuleType(Integer value, String label, boolean repeatCheck, boolean innerSet, boolean visible, UserLevelRuleCategory category) {
			this(value, label, repeatCheck, innerSet, null, visible, category);
		}

		public String serialize(RuleConfig config) {
			return config == null ? "" : JSON.toJSONString(config);
		}

		public RuleConfig deserialize(String configJSONStr) {
			return StringUtil.isEmpty(configJSONStr) ? null : JSONUtil.parseObject(configJSONStr, configClazz);
		}

		public static UserLevelRuleType[] getValues() {
			return ValueProxy.getCachedArray(UserLevelRuleType.class, UserLevelRuleType::values);
		}

		public static UserLevelRuleType of(Integer value) {
			return LOGIN_IN.getValueOf(value);
		}

		public static List<Option<String>> find(UserLevelRuleCategory category) {
			return find(category, null);
		}

		public static UserLevelRuleType[] CACHE = Arrays.stream(values()).filter(UserLevelRuleType::isVisible).toArray(UserLevelRuleType[]::new);

		public static List<Option<String>> find(UserLevelRuleCategory category, UserLevelRuleType filterBasics) {
			final UserLevelRuleType[] values = CACHE;
			List<Option<String>> list = new ArrayList<>(X.size(values));
			for (UserLevelRuleType value : values) {
				if (filterBasics != null && filterBasics == value) {
					continue;
				}
				if (value.category == category) {
					list.add(new Option<>(StringUtil.toString(value.getValue()), value.getLabel()));
				}
			}
			return list;
		}
	}

	public static final String ICON = "icon";
	public static final String NAME = "name";
	public static final String TYPE = "type";
	public static final String RULE_TYPE = "rule_type";
	public static final String MIN_COIN = "min_coin";
	public static final String MAX_LIMIT = "max_limit";
	public static final String BEGIN_TIME = "begin_time";
	public static final String END_TIME = "end_time";
	public static final String CONFIG = "config";
	public static final String SORT = "sort";

}
